package com.storyroad.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONObject;

import com.storyroad.responseClasses.Comment;
import com.storyroad.responseClasses.Story;
import com.storyroad.responseClasses.StoryLinkObject;
import com.storyroad.utils.DBConnection;
import com.storyroad.utils.GetStoryLinks;
import com.storyroad.utils.TableNames;
import com.storyroad.utils.Utilities;

/**
 * Servlet implementation class ReadStory
 */
public class ReadStory extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public ReadStory() {
		super();
		// TODO Auto-generated constructor stub
	}

	/**
	 * Gets the necessary information about a story fragment for displaying it.
	 * @param request HttpServletRequest object that contains data coming from front-end
	 * @param response HttpServletResponse object that contains data which is prepared after processing the incoming data
	 * @throws ServletException
	 * @throws IOException
	 */
	protected void processRequest(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		int f_storyId = Integer.parseInt(request.getParameter("story_id"));
		String f_requestType = request.getParameter("request_type");
		String f_isEdit = request.getParameter("edit");
		String f_username;
		ArrayList<Comment> comments = new ArrayList<Comment>();
		Comment commentObject;
		String username;
		String commentBody;
		int userId;
		Timestamp date;

		if (f_requestType == null || !f_requestType.equals("Android")) {
			f_requestType = "Web";
			f_username = (String)request.getSession().getAttribute("username");
		}
		else{
			f_username = request.getParameter("username");
		}

		Connection conn = new DBConnection().connect();
		Story fetchedStory = new Story();
		PrintWriter out = response.getWriter();
		if (conn == null) {
			out.println("Connection error");
		} else {
			try {
				request.setCharacterEncoding("utf8");
				response.setContentType("application/json");

				// First SQL statement -> getting Story
				PreparedStatement stmt = conn.prepareStatement("SELECT * FROM " + TableNames.STORIES_TABLE + " WHERE s_id = ?");
				stmt.setInt(1, f_storyId);
				ResultSet rs = stmt.executeQuery();
				if (rs.next()) {
					fetchedStory.createStoryObjectFromResultSet(rs);
				}

				// Using Utilities class to get username with u_id
				String userName = Utilities.getUsername(conn, fetchedStory.getOwner());
				fetchedStory.setUserName(userName);
				
				/*
				 * If the owner of the user wants to edit his story fragment, it redirects to EditStory servlet
				 */
				if(f_isEdit!=null && f_isEdit.equals("1")){
					if (f_requestType.equals("Android")) {
						JSONObject jsonObjectFromStoryObject = new JSONObject(fetchedStory);
						String storyObjectToBeReturned = jsonObjectFromStoryObject.toString();
						out.print(storyObjectToBeReturned);
					} else if (f_requestType.equals("Web")) {
						request.setAttribute("storyObject", fetchedStory);
						request.getRequestDispatcher("EditStory.jsp").forward(request, response);
					}
					return;
				}

				String tags = Utilities.getTags(conn, fetchedStory.getS_id());
				fetchedStory.setTags(tags);

				// Get comments of this story
				stmt = conn.prepareStatement("SELECT u_id,date,body FROM " + TableNames.COMMENTS_TABLE
						+ " WHERE s_id = ? ORDER BY date DESC");
				stmt.setInt(1, f_storyId);
				rs = stmt.executeQuery();
				userId = -1;
				username = "";
				while (rs.next()) {
					userId = rs.getInt("u_id");
					username = Utilities.getUsername(conn, rs.getInt("u_id"));
					commentBody = rs.getString("body");
					date = rs.getTimestamp("date");
					commentObject = new Comment(username, commentBody, date);
					comments.add(commentObject);
				}
				fetchedStory.setComments(comments);

				// Get current user's rating for this story.
				fetchedStory.setMyRating(calcMyRating(conn, Utilities.getUserId(conn, f_username), f_storyId));

				// Get profile picture of the owner of this story.
				fetchedStory.setPhotoLink(Utilities.getProfilePicture(conn,	fetchedStory.getUserName()));

				// Get Story Links of this story
				GetStoryLinks getStoryLinksObject = new GetStoryLinks();
				ArrayList<StoryLinkObject> storyLinkList = getStoryLinksObject.getStoryLink(f_storyId);
				fetchedStory.setStoryLinks(storyLinkList);

				// Get titles and bodies of the stories within storyLinkList
				stmt = conn.prepareStatement("SELECT title,body,owner,x_coord,y_coord FROM " + TableNames.STORIES_TABLE + " WHERE s_id = ?");
				Iterator<StoryLinkObject> it = storyLinkList.iterator();
				while (it.hasNext()) {
					int linkedStoryId = it.next().getStory_id();
					stmt.setInt(1, linkedStoryId);
					rs = stmt.executeQuery();
					while (rs.next()) {
						String title = rs.getString("title");
						String body = rs.getString("body");
						String user = Utilities.getUsername(conn, rs.getInt("owner"));
						double coorX = rs.getDouble("x_coord");
						double coorY = rs.getDouble("y_coord");
						fetchedStory.addObjectToStoryTitleMap(linkedStoryId, title);
						fetchedStory.addObjectToStoryBodyMap(linkedStoryId, body);
						fetchedStory.addObjectToStoryUserMap(linkedStoryId, user);
						fetchedStory.addObjectToStoryCoordinateMap(linkedStoryId, coorX, coorY);
					}
				}

				if (f_requestType.equals("Android")) {
					JSONObject jsonObjectFromStoryObject = new JSONObject(fetchedStory);
					String storyObjectToBeReturned = jsonObjectFromStoryObject.toString();
					out.print(storyObjectToBeReturned);
				} else if (f_requestType.equals("Web")) {
					request.setAttribute("storyObject", fetchedStory);
					request.getRequestDispatcher("ViewStory.jsp").forward(request, response);
				}
			} catch (SQLException e) {
				out.print(e.getMessage());
				e.printStackTrace();
			}
			try {
				conn.close();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * Pulls the rating for given user's for the given story.
	 * @param conn connection to the mysql server
	 * @param userId id of the user.
	 * @param storyId id of the story
	 * @return rating of the user for given story.
	 */
	private int calcMyRating(Connection conn, int userId, int storyId) {
		int result = -1;
		PreparedStatement stmt = null;
		ResultSet rs;
		try {
			stmt = conn.prepareStatement("SELECT rating FROM " + TableNames.RATING_TABLE + " WHERE s_id = ? AND u_id = ?");
			stmt.setInt(1, storyId);
			stmt.setInt(2, userId);
			rs = stmt.executeQuery();
			if (rs.next()) {
				result = rs.getInt("rating");
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		processRequest(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		processRequest(request, response);
	}

}
